package com.iflytek.uoamp.notify.core.action;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;

import com.alibaba.fastjson.JSON;
import com.iflytek.uoamp.common.notify.constant.ConstField;
import com.iflytek.uoamp.common.notify.enumerate.ContactState;
import com.iflytek.uoamp.common.notify.enumerate.Type;
import com.iflytek.uoamp.common.notify.exception.NotifyException;
import com.iflytek.uoamp.common.notify.obj.Contact;
import com.iflytek.uoamp.common.notify.obj.Notification;
import com.iflytek.uoamp.common.notify.obj.Period;
import com.iflytek.uoamp.common.notify.plugins.AbstractPlugin;
import com.iflytek.uoamp.common.notify.util.LogInfo;
import com.iflytek.uoamp.common.notify.util.LogbackInstance;
import com.iflytek.uoamp.common.notify.util.NotifyUtils;
import com.iflytek.uoamp.notify.core.dump.DumpTask;
import com.iflytek.uoamp.notify.core.protocol.DumpInfo;
import com.iflytek.uoamp.notify.core.protocol.PluginNode;

public class Dispatcher {
	
	private static LogInfo logInfo = null;
	
	private static final Logger logger = LogbackInstance.getInstance().getLogger(Dispatcher.class);
	
	private Dispatcher() {}
	
	private static class InstanceHolder {
		private static final Dispatcher INSTANCE = new Dispatcher();
	}
	
	public static Dispatcher getInstance(LogInfo logInfo) {
	    Dispatcher.logInfo = logInfo;
		return InstanceHolder.INSTANCE;
	}
	
	public boolean dispatch(Notification notification, long currentTime, boolean useTemplate) throws NotifyException {
		boolean ret = false;
		
		List<?> pluginNodes = notification.getPluginNodes();
		Type type = Type.getType(notification.getType());
		List<?> contents = null;
		List<Contact> contacts = null;
		
        for(Object o : pluginNodes) {
            PluginNode pluginNode = (PluginNode)o;
            
            if(pluginNode.getAllowTime() == null){//默认发送策略
            	contents = getContents(notification, pluginNode);
            	contacts = notification.getContacts();
            	
            	//contents和contacts必须是有效的列表时才允许发送告警信息
                if(contents == null || contacts == null) {
                    continue;
                }
            }
            else{
            	contents = getContents(notification, pluginNode);
            	contacts = getContacts(notification, pluginNode, currentTime);
  
            	//contents和contacts必须是有效的列表时才允许发送告警信息
            	if(contents == null || contacts == null) {
            		continue;
            	}

            	//发送方式不是SEND_ONLY时检查插件的可发送告警时间
            	if(type != Type.SEND_ONLY && !checkTime(pluginNode, currentTime)) {
            		continue;
            	}
            }
            
            AbstractPlugin plugin = NotifyUtils.getPlugin(pluginNode.getPluginType());
            if(plugin == null) {
                logInfo.addInfo(MessageFormat.format(ConstField.NOTCONFIGUREDPLUGIN, pluginNode.getPluginType()));
                continue;
            }
            
            plugin.setNotification(notification);
            plugin.setUseTemplate(useTemplate);
            plugin.setLogInfo(logInfo);
            logger.info("useTemplate ========================="+useTemplate+"contents:"+JSON.toJSONString(contents));
            String text = plugin.getFormatter().pretty(notification, contents);
            logger.info("send text ==========================="+JSON.toJSONString(text));
            if(plugin.sendContent(text, contacts)) {
            	//不需要写数据库
//            	ret = insertNotifyInfo(notification, contents, contacts, plugin, text);
            } else {
            	// ltzeng 发送失败，将通知写入dump文件中，等待dump定时任务重新发送
                writeDumpFile(contacts, text, pluginNode.getPluginType());
                ret = false;
            }
		}
		return ret;
	}
	
	public boolean dispatch(Notification notification, long currentTime) throws NotifyException {
		return dispatch(notification, currentTime, false);
	}
	
	private boolean checkTime(PluginNode plugin, long currentTime)
			throws NotifyException {
		if (plugin == null) {
			return false;
		}

		List<Period> periods = plugin.getAllowTime();
		if (!NotifyUtils.isInPeriods(currentTime, periods)) {
			logInfo.addError(MessageFormat.format(
					ConstField.PLUGINTIMEISNOTACCEPTED, plugin.getPluginType(), 
					new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(currentTime), 
					periods.toString()));
			return false;
		}

		return true;
	}

	private List<?> getContents(Notification notification, PluginNode plugin) {
		List<?> contents = plugin.getContent();

		/** plugin_nodes中的content覆盖外层的content字段 **/
		contents = (contents == null ? notification.getContent() : contents);
		
		if(contents == null || contents.isEmpty()) {
            logInfo.addError(MessageFormat.format(ConstField.BLANKNOTIFICATION, 
                    plugin.getPluginType()));
            return null;
        }
		
		return contents;
	}
	
	private List<Contact> getContacts(Notification notification, PluginNode plugin, long currentTime) throws NotifyException {
		List<Contact> contacts = plugin.getContacts();
		contacts = (contacts == null ? notification.getContacts() : contacts);
		
		Type type = Type.getType(notification.getType());
		if(type != Type.SEND_ONLY && !filterContact(contacts, currentTime, notification.getState())) {
            logInfo.addError(MessageFormat.format(ConstField.DISABLEPLUGIN,
                    plugin.getPluginType(), ConstField.NOPROPERCONTACTS));
            return null;
        }
		
		return contacts;
	}
	
    /**
     * 将未经过联系人检查的对象从contacts数组中移除
     * @param contacts 联系人列表
     * @param currentTime 触发告警事件时的时间戳
     * @param state 当前告警的等级
     * @return 联系人列表大小为0或为null时返回false
     */
    private boolean filterContact(List<Contact> contacts, long currentTime, String state) throws NotifyException{
        List<Contact> removed = new ArrayList<Contact>();
        
        if(contacts == null || contacts.isEmpty()) {
            logInfo.addError(MessageFormat.format(ConstField.DISABLENOTIFICATION,
                    ConstField.NOPROPERCONTACTS));
            return false;
        }
        
        for (Contact contact : contacts) {
            if (!checkContact(contact, state, currentTime)) {
                removed.add(contact);
                continue;
            }
        }
        contacts.removeAll(removed);
        if(contacts.isEmpty()) {
            return false;
        }
        
        return true;
    }
    
    /**
     * 针对每一个联系人检查其告警时间是否在可允许的时间内,检查每一个联系人其告警等级是否在可接受告警的等级列表内
     * @param contact 联系人实体,包含了联系人的姓名、电话、邮件等信息
     * @param state 当前告警事件的等级
     * @param currentTime 触发告警时的时间戳
     * @return
     */
    private boolean checkContact(Contact contact, String state, long currentTime) throws NotifyException{
		List<Period> periods = contact.getAllowTime();
	      
		if(!NotifyUtils.isInPeriods(currentTime, periods)) {
			logInfo.addInfo(MessageFormat.format(ConstField.PASSBYCONTACT, contact.getName(), MessageFormat.format(ConstField.CONTACTTIMEISNOTACCEPTED, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(currentTime), periods)));
			return false;
		}
	      
		if(!NotifyUtils.isInLevel(state, contact.getLevel())) {
			logInfo.addInfo(MessageFormat.format(ConstField.PASSBYCONTACT, contact.getName(), MessageFormat.format(ConstField.STATEISNOTACCEPTED, state, contact.getLevel())));
			return false;
		}
    	return true;
    }
	
	private void writeDumpFile(List<Contact> contacts, String content, 
	        String pluginType) {
        List<Contact> failedContacts = getFailedContacts(contacts);
        
        if(!failedContacts.isEmpty()) {
            DumpInfo dumpInfo = new DumpInfo(failedContacts, content, pluginType);
            DumpTask.writeToFile(dumpInfo);
        }
    }
	
	private List<Contact> getFailedContacts(List<Contact> contacts) {
        List<Contact> failed = new ArrayList<Contact>();
        for(Contact contact : contacts) {
            if(contact.getState() == ContactState.FAILED) {
                failed.add(contact);
            }
            contact.setState(ContactState.UNKNOWN);
        }
        
        return failed;
    }
}
